﻿using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using Notoric.Commanding;
using Notoric.Commanding.CommandBase;

namespace Notoric.Gui.Controls
{
    /// <summary>
    /// Interaction logic for Page.xaml
    /// </summary>
    public partial class Page : UserControl
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="Page"/> instance.
        /// </summary>
        public Page()
        {
            InitializeComponent();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the data context (visualized page) has changed.
        /// </summary>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (page != null)
                page.PropertyChanged -= page_PropertyChanged;

            page = (ViewModel.Elements.Page)DataContext;

            if (page != null)
            {
                page.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(page_PropertyChanged);
                SetPageBorderBindings();
            }
        }

        /// <summary>
        /// Occurs when the user presses the left mouse button in the page area.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void UserControl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            page.ClearSelection();
        }

        /// <summary>
        /// Occurs when the user has drawn a rubber band on the page canvas.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void UserControl_RubberBandDrawn(object sender, RubberBandDrawnEventArgs e)
        {
            var appState = ((App)App.Current).CurrentState;

            if (appState.MouseTarget == GetType())
            {
                if (appState.Command != null)
                {
                    var cmdCreateSection = (UndoableCommandBase)appState.Command;
                    var lengthConverter = new ViewModel.Converters.LengthConverter();
                    var cmdSetPosition = new ViewModel.SetterCommand<double, double>(page.UndoStack, page.RedoStack)
                    {                  
                        Property1 = "Top",
                        Property2 = "Left",
                        Value1 = (double)lengthConverter.ConvertBack(e.Top, typeof(double), null, CultureInfo.CurrentCulture),
                        Value2 = (double)lengthConverter.ConvertBack(e.Left, typeof(double), null, CultureInfo.CurrentCulture)
                    };
                    cmdSetPosition.BindParameterToCommand("Target", cmdCreateSection, "CreatedSection");
                    var cmdSetSize = new ViewModel.SetterCommand<double, double>(page.UndoStack, page.RedoStack)
                    {
                        Property1 = "Height",
                        Property2 = "Width",
                        Value1 = (double)lengthConverter.ConvertBack(e.Height, typeof(double), null, CultureInfo.CurrentCulture),
                        Value2 = (double)lengthConverter.ConvertBack(e.Width, typeof(double), null, CultureInfo.CurrentCulture)
                    };
                    cmdSetSize.BindParameterToCommand("Target", cmdCreateSection, "CreatedSection");

                    var macro = new UndoableMacroCommand(page.UndoStack, page.RedoStack);
                    macro.Commands.Add(cmdSetPosition);
                    macro.Commands.Add(cmdSetSize);
                    macro.Name = cmdCreateSection.Name;

                    Mouse.OverrideCursor = Cursors.Wait;
                    macro.Execute(null);
                    Mouse.OverrideCursor = null;

                    page.ClearSelection();
                    page.SelectSection((ViewModel.Elements.Section)cmdCreateSection.GetUntypedParameterValue("CreatedSection"));

                    appState.Command = null;
                    appState.MouseTarget = null;
                    appState.StatusBarMessage = "Ready";
                    e.Handled = true;
                }
            }
            else
            {
                var rect = new Rect(e.Left, e.Top, e.Width, e.Height);
                page.ClearSelection();

                foreach (var section in page.Sections)
                {
                    var sectionRect = new Rect(section.Left, section.Top, section.Width, section.Height);
                    if (rect.Contains(sectionRect))
                    {
                        page.SelectedSections.Add(section);
                        section.IsSelected = true;
                    }
                }

                e.Handled = true;
            }
        }

        /// <summary>
        /// Occurs when a property of the visualized page has changed.
        /// </summary>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void page_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Orientation")
                SetPageBorderBindings();
            if (e.PropertyName == "SelectedContent")
            {
                if (page.SelectedContent == ViewModel.Elements.SelectedContentType.None)
                    Page_Canvas.DrawRubberBand = true;
                else
                    Page_Canvas.DrawRubberBand = false;
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Sets the bindings of the width and height property of the page border.
        /// </summary>
        private void SetPageBorderBindings()
        {
            var heightBinding = new Binding("Height");
            var widthBinding = new Binding("Width");
            
            heightBinding.Source = widthBinding.Source = page;

            if (page.Orientation == ViewModel.Elements.PageOrientation.Portrait)
            {
                pageBorder.SetBinding(Border.HeightProperty, heightBinding);
                pageBorder.SetBinding(Border.WidthProperty, widthBinding);
            }
            else
            {
                pageBorder.SetBinding(Border.HeightProperty, widthBinding);
                pageBorder.SetBinding(Border.WidthProperty, heightBinding);
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the visualized page.
        /// </summary>
        private ViewModel.Elements.Page page;

        #endregion
    }
}
